<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>vue水果管理 - 新增和修改</title>
  <link rel="stylesheet" href="css/style.css">
</head>

<body>

  <div id="app">
    <!-- 弹层部分（新增、修改） -->
    <div :class="['dialog',{opened: dialogShow}]" style="width:200px;top:10vh;">
      <h3 class="dialog-head">
        <span>{{editId? '修改' : '新增'}}水果</span>
        <span @click="dialogShow = false">&times;</span>
      </h3>

      <form class="dialog-body" autocomplete="off">
        <p>
          <label>水果名称</label><br>
          <input type="text" v-model.trim="form.name" placeholder="请输入水果名称" ref="name">
        </p>
        <p>
          <label>水果单价</label><br>
          <input type="number" v-model="form.price" placeholder="请输入水果单价">
        </p>
      </form>

      <p class="dialog-foot" align="right">
        <button @click="dialogShow = false">取消</button>
        <button @click="onSubmit()">确认</button>
      </p>

    </div>

    <h1 align="center">水果管理</h1>

    <!-- 筛选部分 -->
    <p align="center" class="search">
      <button v-if="selectedList.length" @click="onDelByIds(selectedList)">批量删除</button>
      <input v-model.trim="query.keyword" type="search" placeholder="请输入关键词" size="20">
      <input v-model="query.startPrice" type="number" placeholder="开始价" class="w80">
      <input v-model="query.endPrice" type="number" placeholder="结束价" class="w80">
      <button @click="openDialog()">新增</button>
    </p>

    <!-- 列表部分 -->
    <table class="mytable">
      <thead>
        <tr>
          <th width="60"><input type="checkbox" @change="selectAll" :checked="setAllChecked"></th>
          <th width="60">编号</th>
          <th :class="thCls" @click="onSort('name','string')">名称</th>
          <th width="120" :class="thCls" @click="onSort('price','number')">单价</th>
          <th width="230">操作</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(item, index) in pageData" :key="item.id">
          <td><input type="checkbox" :value="item.id" v-model="selectedList"></td>
          <td>{{(page-1) * pageSize + (index + 1)}}</td>
          <td>{{item.name}}</td>
          <td>{{'¥' + item.price.toFixed(2)}}</td>
          <td>
            <button @click="onMoveUp(item.id)">上移</button>
            <button @click="onMoveDown(item.id)">下移</button>
            <button @click="openDialog(item.id)">修改</button>
            <button @click="onDelByIds([item.id])">删除</button>
          </td>
        </tr>

        <!-- 如果没有数据的话显示这个 -->
        <tr v-if="!searchData.length">
          <td colspan="999" align="center">暂无数据</td>
        </tr>

      </tbody>
    </table>

    <!-- 页码部分 -->
    <p align="center">

      <button :disabled="page <= 1" @click="page--">&lt;</button>

      <button v-for="p in totalPage" :key="p" :class="{active: p === page}" @click="page = p">{{p}}</button>

      <select v-model.number="pageSize">
        <option v-for="item in pageArr" :key="item" :value="item">每页 {{item}} 条</option>
      </select>

      <button :disabled="page >= totalPage" @click="page++">&gt;</button>

      <span>共 {{totalPage}} 页，{{searchData.length}} 条数据</span>
    </p>

  </div>

  <script src="js/vue.global.js"></script>
  <script>
  const vm = Vue.createApp({
      data() {
        return {

          // 水果表数据
          fruits: [
            { id: 1, name: '苹果', price: 8, checked: false },
            { id: 2, name: '桔子', price: 1, checked: false },
            { id: 3, name: '香蕉', price: 5, checked: false },
            { id: 4, name: '甘蔗', price: 12, checked: false },
            { id: 5, name: '橙子', price: 6, checked: false }
          ],

          // 选中的列表( 批量删除的id)
          selectedList: [],

          // 查询条件（1. 关键词 2. 价格区间）
          query: {
            keyword: '',    // 关键词
            startPrice: '', // 开始价
            endPrice: ''    // 结束价
          },

          // 表头排序字段
          sortField: '',    // 排序字段
          sortMethod: '',   // number按数字 string按字符串排序
          sortType: 0,      // 0 默认 1 升序 -1 降序

          // 分页字段
          page: 1,               // 当前页
          pageSize: 2,           // 每页显示条数  
          pageArr: [1, 2, 3, 4, 5],  // 页码数组

          // 弹层显示状态
          dialogShow: false,
          editId: 0,                      // 编辑的id
          form: { name: '', price: '' },  // 表单数据
        }
      },

      // 计算属性
      computed: {

        // 搜索数据
        searchData() {
          // 获取用户输入的查询条件
          const { keyword, startPrice, endPrice } = this.query;

          // 监听查询条件变化，重新搜索，返回搜索的结果
          return this.fruits.filter(item => {
            return item.name.includes(keyword) &&
              (startPrice ? item.price >= startPrice : true) &&
              (endPrice ? item.price <= endPrice : true);
          });
        },

        // 表头排序样式
        thCls() {
          return ['sort', {
            asc: this.sortType === 1,
            desc: this.sortType === -1
          }
          ];
        },

        // 排序数据
        sortData() {

          // 如果排序字段为空，返回搜索结果数据
          if (!this.sortField) return this.searchData;

          // 根据排序字段和排序方法，排序数据
          // 注意：searchData需要浅拷贝，否则排序过后无法恢复到最初的排序之前的状态
          return [...this.searchData].sort((a, b) => {
            if (this.sortMethod === 'number') {
              // 按数值排序
              return (a[this.sortField] - b[this.sortField]) * this.sortType;
            } else {
              // 按字符串排序
              return a[this.sortField].toString().localeCompare(b[this.sortField].toString()) * this.sortType;
            }
          })

        },

        // 计算总页数
        totalPage() {
          return Math.ceil(this.searchData.length / this.pageSize);
        },

        // 计算当前页数据
        pageData() {

          // 防止page越界(2行)
          this.page = this.page > this.totalPage ? this.totalPage : this.page;
          this.page = this.page < 1 ? 1 : this.page;

          const start = (this.page - 1) * this.pageSize;
          const end = start + this.pageSize;
          return this.sortData.slice(start, end);
        },

        // 计算是否全选
        setAllChecked() {
          return this.fruits.length && this.fruits.every(item => this.selectedList.includes(item.id));
        },

      },

      // 方法定义
      methods: {

        // 单击表头排序
        onSort(field, type) {

          this.sortPrevField = this.sortField;

          this.sortType = this.sortType === 0 ? 1 : (this.sortType === 1 ? -1 : 0);
          this.sortField = field;
          this.sortMethod = type;
        },

        // 下移
        onMoveUp(id) {

          // 如果是第一项，则不做任何操作
          if (id === this.sortData[0].id) {
            alert('已经是第一项了');
            return;
          };

          const index = this.fruits.findIndex(item => item.id === id);

          // 缓存当前项
          const temp = this.fruits[index];

          // 交换当前项和上一项
          this.fruits[index] = this.fruits[index - 1];
          this.fruits[index - 1] = temp;

        },

        // 下移
        onMoveDown(id) {

          // 如果是最后一项，则不做任何操作
          if (id === this.sortData[this.fruits.length - 1].id) {
            alert('已经是最后一项了');
            return;
          };

          const index = this.fruits.findIndex(item => item.id === id);

          // 缓存当前项
          const temp = this.fruits[index];

          // 交换当前项和下一项
          this.fruits[index] = this.fruits[index + 1];
          this.fruits[index + 1] = temp;

        },

        // 全选设置selectedList的id值
        selectAll(event) {
          this.selectedList = event.target.checked ? this.fruits.map(item => item.id) : [];
        },

        // 根据Id数组，批量删除数据
        onDelByIds(ids = []) {
          if (!ids.length) {
            alert('请先选择要删除的项');
            return;
          }

          // 确认弹窗
          if (!confirm('确认删除?')) return;

          // 批量删除数据
          this.fruits = this.fruits.filter(item => !ids.includes(item.id));

        },

        // 打开弹层  - 新增（不传editId）、修改（要传editId）
        openDialog( editId = 0 ){

          this.editId = editId; // 缓存到data中，方便其他的函数方法可以获取当前修改的id

          if(editId){
            // 修改

            // 根据id获取当前修改的水果数据
            const { name, price } = this.fruits.find(item => item.id === editId); 
            this.form.name = name;
            this.form.price = price;

          }else{
            // 新增
            this.form = { name: '', price: '' };  // 清空表单数据
          }

          this.dialogShow = true; // 显示弹层

          // 设置打开弹层时，自动聚焦到输入框
          // 必须要弹层显示完成后，再设置focus，否则会无效。
          setTimeout(() => {
            this.$refs.name.focus();  // 原生js的foucs方法
          }, 300);

        },

        // 新增和修改数据处理
        onSubmit(){

          // 获取用户输入的表单数据
          const { name, price } = this.form;

          if(this.editId){
            // 修改
            this.fruits.map(item => {
              if(item.id === this.editId){
                item.name = name;
                item.price = price;
              }
              return item;
            });
          }else{
            // 新增
            this.fruits.unshift({ 
              id: this.fruits.length + 1, 
              name, 
              price, 
            });
          }

          // 关闭弹层
          this.dialogShow = false;

        }

      },

      // 生命周期
      mounted () {

  
        // 监听按键（原生js写法）
        window.onkeydown = (event) => {
          // 按下esc键关闭弹层
          if (event.keyCode ===  27) {
            this.dialogShow = false;
          }
        }
            


      }

    }).mount("#app");
  </script>

</body>

</html>